#include <irrlicht.h>
#include <iostream>
#include <stdio.h>
#include </home/marrabld/Programing/Projects/spellparser/include/irrKlang.h>
#include "game.h"
///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
#include "btBulletDynamicsCommon.h"
#include "basicPhysics.h"

using namespace std;
using namespace irr;
using namespace irrklang;
using namespace videoGame;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#pragma comment(lib, "irrKlang.lib")

gameEngine::gameEngine(bool f, bool m, bool s, bool a, bool v, video::E_DRIVER_TYPE d)
: fullscreen(f), music(m), shadows(s), additive(a), vsync(v),
 driverType(d), device(0),
#ifdef USE_IRRKLANG_not
	//irrKlang(0), ballSound(0), impactSound(0),
#endif
#ifdef USE_SDL_MIXER
	stream(0), ballSound(0), impactSound(0),
#endif
 currentScene(-2), backColor(0), statusText(0), inOutFader(0),
 quakeLevelMesh(0), quakeLevelNode(0), skyboxNode(0), model1(0), model2(0),
 campFire(0), metaSelector(0), mapSelector(0), sceneStartTime(0),
 timeForThisScene(0)
{
    //initalisation constants
    BULLET_MAX_SIZE = 50;
    BULLET_ID = 0;
    ENEMY_ID = 0;
}

// include console I/O methods (conio.h for windows, our wrapper in linux)
#if defined(WIN32)
#include <conio.h>
#else
#include "/home/marrabld/Programing/Projects/spellparser/common/conio.h"
#endif

bool DEBUG_2 = false;

gameState gameEngine::run()
{
	int ScreenResolution_x = 1280;
	int ScreenResolution_y = 760;
	int BitDepth = 32;
	int lastFPS = -1;
	GAME_RUN = 0;
	irr::f32 Time;
	gameState returnType = LOADING;

	 SKeyMap keyMap[8];
         keyMap[0].Action = EKA_MOVE_FORWARD;
         keyMap[0].KeyCode = KEY_UP;
         keyMap[1].Action = EKA_MOVE_FORWARD;
         keyMap[1].KeyCode = KEY_KEY_W;

         keyMap[2].Action = EKA_MOVE_BACKWARD;
         keyMap[2].KeyCode = KEY_DOWN;
         keyMap[3].Action = EKA_MOVE_BACKWARD;
         keyMap[3].KeyCode = KEY_KEY_S;

         keyMap[4].Action = EKA_STRAFE_LEFT;
         keyMap[4].KeyCode = KEY_LEFT;
         keyMap[5].Action = EKA_STRAFE_LEFT;
         keyMap[5].KeyCode = KEY_KEY_A;

         keyMap[6].Action = EKA_STRAFE_RIGHT;
         keyMap[6].KeyCode = KEY_RIGHT;
         keyMap[7].Action = EKA_STRAFE_RIGHT;
         keyMap[7].KeyCode = KEY_KEY_D;

device = createDevice(driverType, core::dimension2d<s32>(ScreenResolution_x, ScreenResolution_y), BitDepth, fullscreen,shadows, false, this);

	 // start the sound engine with default parameters
	 engine = createIrrKlangDevice();
	 engine->play2D("./media/IrrlichtTheme.ogg",true);

	if (device == 0)
		return  DONE; // could not create selected driver.

	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* smgr = device->getSceneManager();

	//Instantiate the timer
	CIrrTimer* Timer = new CIrrTimer(device);
	/*****************************************************************/
	/*-------------------------Physics-------------------------------*/
	/*****************************************************************/

	basicPhysics physics;
	physics.initPhysics();
	
	/*****************************************************************/
	/*---------------------GUI Environment---------------------------*/
	/*****************************************************************/

	gui::IGUIEnvironment* env = device->getGUIEnvironment();
	env->addStaticText(L"-={Dans Double Pendulum Simulation}=-",
	core::rect<int>(10,10,200,22), true);

	env->addImage(driver->getTexture("../../media/opengllogo.png"),core::position2d<s32> (10, 150) );
	env->addImage(driver->getTexture("../../media/irrlichtlogo2.png"),core::position2d<s32>(10, 50));
	env->addImage(driver->getTexture("../../media/bullet-physics-logo-200.jpg"),core::position2d<s32>(1050, 50));

	/*****************************************************************/
	/*----------------------Cameras and lights-----------------------*/
	/*****************************************************************/

        // add white light
        smgr->addLightSceneNode(0, core::vector3df(0,0,0),
                        video::SColorf(0.0f, 0.0f, 0.0f));

        // set ambient light
        smgr->setAmbientLight(video::SColor(0,0,0,0));

	// Add skydome
	smgr->addSkyDomeSceneNode(driver->getTexture("../../media/skydome.jpg"),
		16,	// 16 rows from top to bottom
		16,	// rectangles each row
		0.8f,	// percent of the texture used, example 0.9f will only use the top 90% of the image file (range 0.0f-1.0f)
		2.0f);	// percent of the sphere to cover 1.0f covers the top half of the sphere, while 2.0f covers the entire sphere

	// create test cube
        scene::ISceneNode* test = smgr->addSphereSceneNode(20);
	scene::ISceneNode* test_2 = smgr->addSphereSceneNode(20);

        // let the cube rotate and set some light settings
    //    scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(
    //            core::vector3df(0.3f, 0.3f,0));

        test->setPosition(core::vector3df(0,0,500));
	test->setMaterialTexture(0, driver->getTexture("../../media/t351sml.jpg"));
        test->setMaterialFlag(video::EMF_LIGHTING, false); // disable dynamic lighting

	test_2->setPosition(core::vector3df(0,0,1000));
	test_2->setMaterialTexture(0, driver->getTexture("../../media/t351sml.jpg"));
	test_2->setMaterialFlag(video::EMF_LIGHTING, false);

	// Add a big box to act as the ground
	//scene::ISceneNode* floor = smgr->addCubeSceneNode(1000);
	scene::IAnimatedMesh* roomMesh = smgr->getMesh(
		"../../media/Landscape.3ds");

	smgr->getMeshManipulator()->makePlanarTextureMapping(
				roomMesh->getMesh(0), 0.003f);

	// Scale the mesh using the manipulator
	scene::IMeshManipulator *manipulator = smgr->getMeshManipulator();
	core::matrix4 m;
        m.setScale ( core::vector3df(1,0.1,1) );
        manipulator->transformMesh( roomMesh, m );

	scene::ISceneNode* room = 0;
		video::ITexture* colorMap =
			//driver->getTexture("../../media/rockwall.bmp");
			driver->getTexture("../../media/wall.jpg");
		video::ITexture* normalMap =
			//driver->getTexture("../../media/terrain-heightmap.bmp");
			driver->getTexture("../../media/rockwall_height.bmp");

		driver->makeNormalMapTexture(normalMap, 90.0f);

		scene::IMesh* tangentMesh = smgr->getMeshManipulator()->createMeshWithTangents(
			roomMesh->getMesh(0));

		room = smgr->addMeshSceneNode(tangentMesh);
		room->setMaterialTexture(0, colorMap);
		room->setMaterialTexture(1, normalMap);

		room->getMaterial(0).SpecularColor.set(0,0,0,0);

		room->setMaterialFlag(video::EMF_FOG_ENABLE, false);
		room->setMaterialType(video::EMT_PARALLAX_MAP_SOLID);
		// adjust height for parallax effect
		room->getMaterial(0).MaterialTypeParam = 0.035f;

		// drop mesh because we created it with a create.. call.
		tangentMesh->drop();
	
	room->setPosition(core::vector3df(0,-300,0));
	//room->setMaterialTexture(0, driver->getTexture("../../media/stones.jpg"));
	room->setMaterialFlag(video::EMF_LIGHTING, true); // disable dynamic lighting
	room->setMaterialFlag(video::EMF_FOG_ENABLE, false);

	driver->setFog(video::SColor(0,138,125,81), true, 250, 1000, 0, true);

	// add light 1 (nearly red)
	scene::ILightSceneNode* light1 =
		smgr->addLightSceneNode(0, core::vector3df(0,-200,0),
		video::SColorf(1.0f, 1.0f, 1.0f, 1.0f), 100000.0f);


	// add fly circle animator to light 1
	scene::ISceneNodeAnimator* anim =
		smgr->createFlyCircleAnimator (core::vector3df(0,-200,0),190.0f, -0.0003f);
	light1->addAnimator(anim);
	anim->drop();

	// attach billboard to the light
	scene::ISceneNode* bill =
		smgr->addBillboardSceneNode(light1, core::dimension2d<f32>(60, 60));

	bill->setMaterialFlag(video::EMF_LIGHTING, false);
	bill->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
	bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
	bill->setMaterialTexture(0, driver->getTexture("../../media/particlered.bmp"));
	
	//////////////////
 	// Set position //
	//////////////////

	if(physics.body && test && test_2)
{
	btVector3 testVector = physics.body->getCenterOfMassPosition();
	btVector3 testVector_2 = physics.body_2->getCenterOfMassPosition();

	// physics.getPhysicsPos();

	const core::vector3df v ((f32)testVector[0],(f32)testVector[1] , (f32)testVector[2]);
	const core::vector3df v_2 ((f32)testVector_2[0],(f32)testVector_2[1] , (f32)testVector_2[2]);

	assert (0 != test);
	test->setPosition(v); 

	assert (0 != test_2);
	test_2->setPosition(v_2);
}
	else
{
	cout<<"error!"<<endl;
}

    	// Add Content pipeline here, possibly read an xml file to load objects into the world
 	btVector3 testGravity; // = new btVector3(0,0,0);

     	// add fps camera
        scene::ICameraSceneNode* fpsCamera = smgr->addCameraSceneNodeFPS();
        fpsCamera->setPosition(core::vector3df(0,100,-300));

/*********************************************************************************************************/
/*                                      Main Drawing Loop                                                */
/*********************************************************************************************************/

	while(device->run() && driver && GAME_RUN == 0)
	if (device->isWindowActive())
	{
	    //Start the timer
	    Timer->Update();
	    Time = Timer->m_TimeFactor;

        	driver->beginScene(true, true, video::SColor(255,200,200,200));

		smgr->drawAll();
		env->drawAll();

		//Update the physics world
		physics.m_dynamicsWorld->stepSimulation(Time*10,7);

		// syncronise the two worlds.
		btVector3 testVector = physics.body->getCenterOfMassPosition();
		btVector3 testVector_2 = physics.body_2->getCenterOfMassPosition();
		const core::vector3df v ((f32)testVector[0],(f32)testVector[1] , (f32)testVector[2]);
		const core::vector3df v_2 ((f32)testVector_2[0],(f32)testVector_2[1] , (f32)testVector_2[2]);
			
		if (DEBUG_2 == true)
		{
		btVector3 testGravity = physics.body_2->getGravity();
		//const core::vector3df
		cout<<"Gravity on Body_2 "<<(f32)testGravity[0]<<"   "<<(f32)testGravity[1]<<"   "<<(f32)testGravity[2]<<endl;
		cout<<"body   "<<(f32)testVector[0]<<"   "<<(f32)testVector[1]<<"   "<<(f32)testVector[2]<<endl;
		cout<<"body_2 "<<(f32)testVector_2[0]<<"   "<<(f32)testVector_2[1]<<"   "<<(f32)testVector_2[2]<<endl;
		}

		assert (0 != test_2);
		test_2->setPosition(v_2);
	
		assert (0 != test);
		test->setPosition(v); 

		driver->draw3DLine(v,v_2,SColor(255,255,255,0));
		driver->draw3DLine(core::vector3df(0,0,0),v,SColor(255,255,255,0));

		driver->endScene();

		int fps = driver->getFPS();

		if (lastFPS != fps)
		{
		  core::stringw str = L"My Crappy game using -> Irrlicht Engine and Bullet Physics Engine [";
		  str += driver->getName();
		  str += "] FPS:";
		  str += fps;

		  device->setWindowCaption(str.c_str());
		  lastFPS = fps;
		}
    Timer->Reset();
	}

	device->drop();
	engine->drop();
	physics.exitPhysics();
return  returnType;
}

gameEngine::~gameEngine()
{
	if (mapSelector)
		mapSelector->drop();

	if (metaSelector)
		metaSelector->drop();

#ifdef USE_IRRKLANG
	if (irrKlang)
		irrKlang->drop();
#endif
}

bool gameEngine::OnEvent(const SEvent& event) //Event Handler
{

      if (event.EventType == EET_MOUSE_INPUT_EVENT)
   {
      switch(event.MouseInput.Event)
      {
         //! Left mouse button was pressed down.
         case EMIE_LMOUSE_PRESSED_DOWN:// = 0,
            {
               // shoot();
                break;
            }
         //! Right mouse button was pressed down.
         case EMIE_RMOUSE_PRESSED_DOWN:
             {
               // fire();
                break;
             }
         //! Middle mouse button was pressed down.
         case EMIE_MMOUSE_PRESSED_DOWN:

            break;
         //! Left mouse button was left up.
         case EMIE_LMOUSE_LEFT_UP:

            break;
         //! Right mouse button was left up.
         case EMIE_RMOUSE_LEFT_UP:

            break;
         //! Middle mouse button was left up.
         case EMIE_MMOUSE_LEFT_UP:

            break;
         //! The mouse cursor changed its position.
         case EMIE_MOUSE_MOVED:
         {
#ifdef _DEBUG
            //spits out the x,y coords for the mouse position
            //helpful for designing a layout or sizing Gui items
            char cpos[12];
            wchar_t pos[12];
            for(int j=0;j<12;j++) //pre-format the string data
            {
               cpos[j] = '\0';
               pos[j]='\0';
            }

            wsprintf(cpos,"%u %u",device->getCursorControl()->getPosition());
            wprintf(L"x:%u y:%u\n", device->getCursorControl()->getPosition());
            mbstowcs(pos , cpos , 12);
            device->setWindowCaption(&pos[0]);

#endif
            break;
         }

         default:

            break;

      }
   }

else

	{
		switch(event.KeyInput.Key)
		{
		case KEY_ESCAPE:
		{
            	GAME_RUN = 1;
		returnType = LOADING;
            	break;
		}
		case KEY_KEY_Q:
		{
		GAME_RUN = 1;
		returnType = DONE;
		 break;
		}

		case KEY_SPACE:
        	{
            //	shoot();
            	break;

		}
			return true;
		}
} return false;
 } ;

